import numpy as np
from numpy.lib.stride_tricks import sliding_window_view #这是numpy中的高级模块，可以生成一个滑动的窗口类似于卷积核。
from PIL import Image
import torch
from torchvision import transforms
#--------------------------------------编写一个方法，把正常的rgb图像转换为暗通道图---------------------------------------
def rgb_to_dark_channel(image, patch_size=15):
    """
       将RGB图像转换为暗通道图
       :param image: 输入RGB图像，形状为[H, W, 3]的numpy数组，值域0-255 numpy数组
       :param patch_size: 局部窗口大小（必须为奇数，若不是奇数会自动+1处理）
       :return: 暗通道图，形状与输入图像前两维相同
       """
    """
    核心实现思路是，先取每个像素在三个通道上的最小值。
    然后用滑动窗口去一个个取min值组装成暗通道图
    最后输出暗通道图，应该是以numpy数组的形式输出。
    """
    # 确保窗口大小为奇数
    patch_size = patch_size if patch_size % 2 == 1 else patch_size + 1  #py中的三元表达式也称条件表达式
    radius = patch_size // 2 #这个符号在python中是整除，向下取整。可是这里为什么要算这个值

    # Step 1: 计算每个像素的RGB最小值
    min_channel = np.min(image, axis=2) #这个操作是在第三维度就是像素三个通道的维度找到最小值，这个操作会降维，最后输出的是二维numpy数组，格式为[H,W]
    # Step 2: 图像填充（边缘填充NaN）
    padded = np.pad(
        min_channel.astype(np.float32),  # 转为float以支持NaN，NaN是浮点数支持的值，整数不支持
        pad_width=radius, #这个代表填充的半径，表示在一个numpy数组的边缘（这个时候得想象成立体的），这样填充是为了边缘也能进行滑动处理
        mode="constant", #这里声明了填充模式，这代表用常数填充
        #填充模式还有边缘填充和镜像填充，这两种填充模式都不需要指定填充值，之后见到再说吧
        constant_values=np.nan #这个是填充的值，填充的值是NaN，np.nan代表这个值，这个值代表的数据不会参与大小比较和运算
    )#这个方法的第一个参数就是要操作的数组，这个padded返回的是一个填充好的数组
    # Step 3: 创建滑动窗口视图（高效实现）
    windows = sliding_window_view(padded, (patch_size, patch_size)) #这个最后返回一个四维数组，其实就是元素替换为（patch_size,patch_size）的三维数组
    # Step 4: 计算每个窗口的最小值（自动忽略NaN）
    dark_channel = np.nanmin(windows, axis=(2, 3)) #nanmin会忽略nan，但是min会将nan当做正常值参与运算。axis这个参数你就学吧
    # 处理全为NaN的窗口（设置为0）
    dark_channel = np.nan_to_num(dark_channel, nan=0.0) #这个方法是替换nan的值，这个操作如果图像正常是不需要的，这里写入是提高算法鲁棒性
    #上述将nan值设定为0，是为了防止之后对于大气光值估计的时候取到这些nan值点。
    #返回暗通道图的numpy数组
    return dark_channel.astype(np.uint8)#转换为整形
#-------------------------------------------------------TEST----------------------------------------------------------
image =Image.open("D:\dehaze\kong.jpg")
#image.show()
image = np.array(image)
dark_image = rgb_to_dark_channel(image,patch_size=50)
#此时dark_image应该是一个二维的numpy数组对应的是灰度图
dark_image=Image.fromarray(dark_image)
#dark_image.show()
#这里来看一下[H,W,3]的numpy数组的构成，很有意思。
"""
image = np.array(
    [[[255, 0, 0],    # 左上角：纯红色
     [0, 255, 0]],   # 右上角：纯绿色
    [[0, 0, 255],    # 左下角：纯蓝色
     [100, 100, 100]]]  # 右下角：灰色
, dtype=np.uint8)
print(image.shape)  # 输出: (2, 2, 3)
这是一个2x2的像素图，
对于一个像素其值为[R,G,B],所以第三个维度对应的是[R,G,B],懒得说了自己看吧
"""
#研究一下所取局部区域大小对结果的影响